Skip to content

OCPBUGS-78542: fix useHistory crash and null safety guards#178

Open
upalatucci wants to merge 2 commits intoopenshift:mainfrom
upalatucci:fix-crash-nncp-form
Open

OCPBUGS-78542: fix useHistory crash and null safety guards#178
upalatucci wants to merge 2 commits intoopenshift:mainfrom
upalatucci:fix-crash-nncp-form

Conversation

@upalatucci
Copy link

Summary

  • Migrate all useHistory (React Router v5) calls to useNavigate from react-router-dom-v5-compat, fixing useHistory is not a function runtime crash in the console plugin
  • Fix useSignalEffect returning null instead of undefined as cleanup function
  • Add null safety guards to prevent TypeError: n is not iterable crashes when spreading potentially undefined values (interfaces, ports, ownerReferences, nodes)
  • Fix unsafe .find().type access in getEnactmentStatus with optional chaining

Test plan

  • Verify Topology view loads without useHistory is not a function error
  • Verify Topology view loads without n is not iterable error
  • Verify navigation (create policy, edit policy, delete policy) works correctly with useNavigate
  • Verify Physical Networks page navigation works
  • Verify Policy list page create buttons navigate correctly
  • Verify NNS list page topology toggle navigates correctly

Made with Cursor

@openshift-ci-robot openshift-ci-robot added jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. labels Mar 16, 2026
@openshift-ci-robot
Copy link

@upalatucci: This pull request references Jira Issue OCPBUGS-78542, which is valid.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (4.22.0) matches configured target version for branch (4.22.0)
  • bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

Summary

  • Migrate all useHistory (React Router v5) calls to useNavigate from react-router-dom-v5-compat, fixing useHistory is not a function runtime crash in the console plugin
  • Fix useSignalEffect returning null instead of undefined as cleanup function
  • Add null safety guards to prevent TypeError: n is not iterable crashes when spreading potentially undefined values (interfaces, ports, ownerReferences, nodes)
  • Fix unsafe .find().type access in getEnactmentStatus with optional chaining

Test plan

  • Verify Topology view loads without useHistory is not a function error
  • Verify Topology view loads without n is not iterable error
  • Verify navigation (create policy, edit policy, delete policy) works correctly with useNavigate
  • Verify Physical Networks page navigation works
  • Verify Policy list page create buttons navigate correctly
  • Verify NNS list page topology toggle navigates correctly

Made with Cursor

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai
Copy link

coderabbitai bot commented Mar 16, 2026

Walkthrough

This pull request introduces defensive null-safety handling in utility functions and migrates React Router navigation from the deprecated useHistory hook to useNavigate via react-router-dom-v5-compat across multiple view and component files.

Changes

Cohort / File(s) Summary
Utility null-safety improvements
src/utils/components/.../useNodeInterfaces/utils/utils.ts, src/utils/resources/enactments/utils.ts, src/utils/resources/policies/utils.ts, src/views/nodenetworkconfiguration/utils/utils.ts
Added optional chaining and fallback empty arrays to prevent spread of undefined values in port mapping, enactment status lookup, node filtering, and interface/enactment resolution.
Topology navigation migration
src/views/nodenetworkconfiguration/Topology.tsx, src/views/nodenetworkconfiguration/components/TopologySidebar/CreatePolicyDrawer.tsx, src/views/nodenetworkconfiguration/components/TopologySidebar/InterfaceDrawer/TopologyDrawer.tsx, src/views/nodenetworkconfiguration/components/TopologyToolbar/TopologyToolbar.tsx
Replaced useHistory with useNavigate from react-router-dom-v5-compat; updated navigation calls from history.push() to navigate().
Physical networks navigation migration
src/views/physical-networks/components/PhysicalNetworksEmptyState.tsx, src/views/physical-networks/components/PhysicalNetworksPageHeader.tsx, src/views/physical-networks/components/PhysicalNetworksTable/components/PhysicalNetworkRow/PhysicalNetworkRow.tsx, src/views/physical-networks/components/PhysicalNetworksTable/components/PhysicalNetworkRow/utils/utils.tsx
Migrated from useHistory to useNavigate hook; updated history.push() calls to navigate(). Function signature in utils updated to accept navigate callback instead of history object.
Policies navigation migration
src/views/policies/actions/PolicyActions.tsx, src/views/policies/components/DeleteModal.tsx, src/views/policies/list/components/CreatePolicyButtons.tsx, src/views/policies/new/NewPolicy.tsx
Replaced useHistory with useNavigate from react-router-dom-v5-compat; updated all history.push() and history.goBack() calls to navigate() equivalents.
States navigation migration
src/views/states/list/hooks/useDrawerInterface.ts
Updated router hook from useHistory to useNavigate; replaced history.push() calls with navigate() for list and query navigation.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can enable review details to help with troubleshooting, context usage and more.

Enable the reviews.review_details setting to include review details such as the model used, the time taken for each step and more in the review comments.

@openshift-ci openshift-ci bot requested review from avivtur and tnisan March 16, 2026 17:06
@openshift-ci
Copy link

openshift-ci bot commented Mar 16, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: upalatucci

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Mar 16, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/views/nodenetworkconfiguration/components/TopologySidebar/CreatePolicyDrawer.tsx (1)

78-82: ⚠️ Potential issue | 🟠 Major

Use absolute path and construct query parameters consistently

Line 80 uses a relative path and direct template interpolation for the query parameter, which is inconsistent with other navigate calls in the codebase (lines 32 and 90 use absolute paths like /node-network-configuration). The preferred pattern in this codebase (TopologyToolbar.tsx line 47) is to use URLSearchParams with the location object format. This ensures consistent routing behavior and proper URL encoding.

Suggested fix
       navigate(
         createAnotherPolicy
-          ? `node-network-configuration?createPolicy=true&physicalNetworkName=${networkName}`
+          ? `${createAnotherPolicy ? `/node-network-configuration?createPolicy=true&physicalNetworkName=${encodeURIComponent(networkName)}` : ''}`

Or preferably, match the TopologyToolbar pattern:

+      const navigationParams = new URLSearchParams({
+        [CREATE_POLICY_QUERY_PARAM]: 'true',
+        'physicalNetworkName': networkName,
+      });
       navigate(
         createAnotherPolicy
-          ? `node-network-configuration?createPolicy=true&physicalNetworkName=${networkName}`
+          ? { pathname: '/node-network-configuration', search: navigationParams.toString() }
           : getResourceUrl({ model: NodeNetworkConfigurationPolicyModel, resource: createdPolicy }),
       );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/views/nodenetworkconfiguration/components/TopologySidebar/CreatePolicyDrawer.tsx`
around lines 78 - 82, The navigate call that builds the URL when
createAnotherPolicy is true uses a relative path and direct interpolation of
networkName; change it to use the absolute path "/node-network-configuration"
and construct query parameters via URLSearchParams (or the location object form)
to match the project's pattern (see TopologyToolbar). Update the ternary branch
in the navigate invocation that references createAnotherPolicy to build the
destination like { pathname: '/node-network-configuration', search: new
URLSearchParams({ createPolicy: 'true', physicalNetworkName: networkName
}).toString() } while leaving the existing
getResourceUrl(NodeNetworkConfigurationPolicyModel, createdPolicy) branch
intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/utils/resources/enactments/utils.ts`:
- Around line 3-4: getEnactmentStatus currently can return undefined even though
it's typed as string; update the function (getEnactmentStatus with parameter
V1beta1NodeNetworkConfigurationEnactment) to return a concrete default status
when no condition with status === 'True' is found (e.g., return 'Unknown' or
'Pending') so callers always receive a string and downstream grouping/filtering
won't break.

In `@src/views/nodenetworkconfiguration/utils/utils.ts`:
- Around line 224-225: The function getCorrelatedEnactment currently declares a
non-optional return but uses .find() and can return undefined; change its
signature to return the NNCE type as optional (e.g., NNCE | undefined) and
update any parameter types that assume a non-null value accordingly, and then
update callers such as getNNCEConfiguredInterfaces to accept the optional return
(adjust its parameter type to accept undefined) so the type contract matches the
runtime null-safe behavior.

---

Outside diff comments:
In
`@src/views/nodenetworkconfiguration/components/TopologySidebar/CreatePolicyDrawer.tsx`:
- Around line 78-82: The navigate call that builds the URL when
createAnotherPolicy is true uses a relative path and direct interpolation of
networkName; change it to use the absolute path "/node-network-configuration"
and construct query parameters via URLSearchParams (or the location object form)
to match the project's pattern (see TopologyToolbar). Update the ternary branch
in the navigate invocation that references createAnotherPolicy to build the
destination like { pathname: '/node-network-configuration', search: new
URLSearchParams({ createPolicy: 'true', physicalNetworkName: networkName
}).toString() } while leaving the existing
getResourceUrl(NodeNetworkConfigurationPolicyModel, createdPolicy) branch
intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f348e9b3-aee3-421d-8146-36eb2c7583ca

📥 Commits

Reviewing files that changed from the base of the PR and between d597f71 and 57f2cfc.

📒 Files selected for processing (17)
  • src/utils/components/PolicyForm/PolicyWizard/utils/hooks/useNodeInterfaces/utils/utils.ts
  • src/utils/resources/enactments/utils.ts
  • src/utils/resources/policies/utils.ts
  • src/views/nodenetworkconfiguration/Topology.tsx
  • src/views/nodenetworkconfiguration/components/TopologySidebar/CreatePolicyDrawer.tsx
  • src/views/nodenetworkconfiguration/components/TopologySidebar/InterfaceDrawer/TopologyDrawer.tsx
  • src/views/nodenetworkconfiguration/components/TopologyToolbar/TopologyToolbar.tsx
  • src/views/nodenetworkconfiguration/utils/utils.ts
  • src/views/physical-networks/components/PhysicalNetworksEmptyState.tsx
  • src/views/physical-networks/components/PhysicalNetworksPageHeader.tsx
  • src/views/physical-networks/components/PhysicalNetworksTable/components/PhysicalNetworkRow/PhysicalNetworkRow.tsx
  • src/views/physical-networks/components/PhysicalNetworksTable/components/PhysicalNetworkRow/utils/utils.tsx
  • src/views/policies/actions/PolicyActions.tsx
  • src/views/policies/components/DeleteModal.tsx
  • src/views/policies/list/components/CreatePolicyButtons.tsx
  • src/views/policies/new/NewPolicy.tsx
  • src/views/states/list/hooks/useDrawerInterface.ts

Comment on lines 3 to +4
export const getEnactmentStatus = (enactment: V1beta1NodeNetworkConfigurationEnactment): string =>
enactment?.status?.conditions?.find((condition) => condition.status === 'True').type;
enactment?.status?.conditions?.find((condition) => condition.status === 'True')?.type;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Return a concrete default status instead of allowing undefined

Line 4 can now evaluate to undefined, but getEnactmentStatus is typed as string and callers use the result as a status key/value. This can silently create undefined entries and break filtering/state grouping behavior downstream.

Suggested fix
 export const getEnactmentStatus = (enactment: V1beta1NodeNetworkConfigurationEnactment): string =>
-  enactment?.status?.conditions?.find((condition) => condition.status === 'True')?.type;
+  enactment?.status?.conditions?.find((condition) => condition.status === 'True')?.type ?? 'Pending';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const getEnactmentStatus = (enactment: V1beta1NodeNetworkConfigurationEnactment): string =>
enactment?.status?.conditions?.find((condition) => condition.status === 'True').type;
enactment?.status?.conditions?.find((condition) => condition.status === 'True')?.type;
export const getEnactmentStatus = (enactment: V1beta1NodeNetworkConfigurationEnactment): string =>
enactment?.status?.conditions?.find((condition) => condition.status === 'True')?.type ?? 'Pending';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/resources/enactments/utils.ts` around lines 3 - 4,
getEnactmentStatus currently can return undefined even though it's typed as
string; update the function (getEnactmentStatus with parameter
V1beta1NodeNetworkConfigurationEnactment) to return a concrete default status
when no condition with status === 'True' is found (e.g., return 'Unknown' or
'Pending') so callers always receive a string and downstream grouping/filtering
won't break.

Comment on lines +224 to +225
return availableEnhancments?.find((nnce) =>
nnce.metadata?.ownerReferences?.some((ref) => ref.name === nnsName),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Function signature and return expression =="
rg -n -C2 'const getCorrelatedEnactment|availableEnhancments\?\.\s*find|V1beta1NodeNetworkConfigurationEnactment' src/views/nodenetworkconfiguration/utils/utils.ts

echo
echo "== TypeScript strictness flags in tsconfig files =="
fd 'tsconfig.*json' -t f | while read -r f; do
  echo "-- $f --"
  rg -n '"strict"\s*:|"strictNullChecks"\s*:' "$f" || true
done

Repository: openshift/nmstate-console-plugin

Length of output: 1204


🏁 Script executed:

# Search for all usages of getCorrelatedEnactment
rg -n 'getCorrelatedEnactment' src/views/nodenetworkconfiguration/utils/utils.ts

# Also check if it's exported and used elsewhere
rg -r 'getCorrelatedEnactment' src/ --type ts --type tsx

Repository: openshift/nmstate-console-plugin

Length of output: 239


🏁 Script executed:

# Get context around the function call at line 179 to see how the result is used
rg -n -A 10 -B 5 'const enhancment = getCorrelatedEnactment' src/views/nodenetworkconfiguration/utils/utils.ts

Repository: openshift/nmstate-console-plugin

Length of output: 702


🏁 Script executed:

# Get the full implementation of getNNCEConfiguredInterfaces
rg -n -A 20 'const getNNCEConfiguredInterfaces' src/views/nodenetworkconfiguration/utils/utils.ts

Repository: openshift/nmstate-console-plugin

Length of output: 793


Type contract no longer matches actual return value.

getCorrelatedEnactment can return undefined when .find() yields no match, but the function signature declares a non-optional return type. The downstream caller getNNCEConfiguredInterfaces defends against this with an isEmpty check, but this masks a type contract mismatch that weakens maintainability. Align both the parameter and return types with the null-safe behavior:

Proposed fix
const getCorrelatedEnactment = (
-  availableEnhancments: V1beta1NodeNetworkConfigurationEnactment[],
+  availableEnhancments: V1beta1NodeNetworkConfigurationEnactment[] | undefined,
   nnsName: string,
-): V1beta1NodeNetworkConfigurationEnactment => {
+): V1beta1NodeNetworkConfigurationEnactment | undefined => {
   return availableEnhancments?.find((nnce) =>
     nnce.metadata?.ownerReferences?.some((ref) => ref.name === nnsName),
   );
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/views/nodenetworkconfiguration/utils/utils.ts` around lines 224 - 225,
The function getCorrelatedEnactment currently declares a non-optional return but
uses .find() and can return undefined; change its signature to return the NNCE
type as optional (e.g., NNCE | undefined) and update any parameter types that
assume a non-null value accordingly, and then update callers such as
getNNCEConfiguredInterfaces to accept the optional return (adjust its parameter
type to accept undefined) so the type contract matches the runtime null-safe
behavior.

@openshift-ci
Copy link

openshift-ci bot commented Mar 16, 2026

@upalatucci: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants